/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
 * This file constains code of cpu debug and npu code.We read data from bin file
 * and write result to file.
 */
#include "data_utils.h"
#include <chrono>
#ifndef __CCE_KT_TEST__
#include "acl/acl.h"
extern void matmul_custom_do(uint32_t coreDim, void *l2ctrl, void *stream,
                             uint8_t *param1, uint8_t *param2, uint8_t *param3);
#else
#include "tikicpulib.h"
extern "C" void matmul_custom(uint8_t *param1, uint8_t *param2, uint8_t *param3);
#endif

int32_t main(int32_t argc, char *argv[])
{
    size_t M, N, K;
    M = 8192;
    K = 68416;
    N = 256;
    size_t param1FileSize = M * K * sizeof(uint16_t); // uint16_t represent half
    size_t param2FileSize = K * N * sizeof(uint16_t); // uint16_t represent half
    size_t param3FileSize = M * N * sizeof(float);
    uint32_t blockDim = 30;

#ifdef __CCE_KT_TEST__
    uint8_t *param1 = (uint8_t *)AscendC::GmAlloc(param1FileSize);
    uint8_t *param2 = (uint8_t *)AscendC::GmAlloc(param2FileSize);
    uint8_t *param3 = (uint8_t *)AscendC::GmAlloc(param3FileSize);

    ReadFile("./input/x1_gm.bin", param1FileSize, param1, param1FileSize);
    ReadFile("./input/x2_gm.bin", param2FileSize, param2, param2FileSize);

    ICPU_RUN_KF(matmul_custom, blockDim, param1, param2, param3);

    WriteFile("./output/output.bin", param3, param3FileSize);

    AscendC::GmFree((void *)param1);
    AscendC::GmFree((void *)param2);
    AscendC::GmFree((void *)param3);
#else

    CHECK_ACL(aclInit(nullptr));
    aclrtContext context;
    int32_t deviceId = 0;
    CHECK_ACL(aclrtSetDevice(deviceId));
    CHECK_ACL(aclrtCreateContext(&context, deviceId));
    aclrtStream stream = nullptr;
    CHECK_ACL(aclrtCreateStream(&stream));

    uint8_t *param1Host;
    uint8_t *param1Device;
    CHECK_ACL(aclrtMallocHost((void **)(&param1Host), param1FileSize));
    CHECK_ACL(aclrtMalloc((void **)&param1Device, param1FileSize, ACL_MEM_MALLOC_HUGE_FIRST));
    ReadFile("./input/x1_gm.bin", param1FileSize, param1Host, param1FileSize);
    CHECK_ACL(aclrtMemcpy(param1Device, param1FileSize, param1Host, param1FileSize, ACL_MEMCPY_HOST_TO_DEVICE));

    uint8_t *param2Host;
    uint8_t *param2Device;
    CHECK_ACL(aclrtMallocHost((void **)(&param2Host), param2FileSize));
    CHECK_ACL(aclrtMalloc((void **)&param2Device, param2FileSize, ACL_MEM_MALLOC_HUGE_FIRST));
    ReadFile("./input/x2_gm.bin", param2FileSize, param2Host, param2FileSize);
    CHECK_ACL(aclrtMemcpy(param2Device, param2FileSize, param2Host, param2FileSize, ACL_MEMCPY_HOST_TO_DEVICE));

    uint8_t *param3Host;
    uint8_t *param3Device;
    CHECK_ACL(aclrtMallocHost((void **)(&param3Host), param3FileSize));
    CHECK_ACL(aclrtMalloc((void **)&param3Device, param3FileSize, ACL_MEM_MALLOC_HUGE_FIRST));
    std::cout << "乘法开始\n";
      for (int i = 0; i < 5; i++)
      {
        CHECK_ACL(aclrtSynchronizeStream(stream));
        auto start = std::chrono::high_resolution_clock::now();

        matmul_custom_do(blockDim, nullptr, stream, param1Device, param2Device, param3Device);

        CHECK_ACL(aclrtSynchronizeStream(stream));
        auto end = std::chrono::high_resolution_clock::now();

        std::chrono::duration<double> diff = (end - start) * 1000;
        std::cout << "第" << i << "轮乘法耗时为: " << diff.count() << " ms\n";
      }
    // int m, n,  group_size, B_Split_W, window_H, window_W, split_K; 
    // m = 8192;
    // // int k = 68416;
    // n = 256;
    // int max_limit;
    // int block_sum = 30;
    // int n_divide_16 = n / 16;
    // int A0_size = 32768; // A0空间大小为 65536字节，可存放half数据多少个

    // int C0_size = 65536;
    // if (n_divide_16 % 2 == 0) // 直接分两组
    // {
    //     group_size = block_sum / 2; // 每组aicore的数目
    //     B_Split_W = n / 2;          // B做列切,(确保16的倍数)

    //     window_H = (m / group_size) > (C0_size / B_Split_W) ? (C0_size / B_Split_W) : (m / group_size); // 先定window_H，受到C0制约
    //     window_H = window_H / 16 * 16; //(确保16的倍数)                                                                                        // 令window_H为16的倍数

    //     max_limit = B_Split_W > window_H ? B_Split_W : window_H; // A0的window_H和B0的B_Split_W都会对window_W的选取产生影响
    //     window_W = A0_size / max_limit;
    //     window_W = window_W / 16 * 16; //(确保16的倍数) 
    //     split_K = window_W; // A1和B1这样的绝不会溢出和犯错
    // }
    // printf("window_H = %d, B_Split_W = %d, split_K = %d, window_W = %d, group_size = %d\n", window_H, B_Split_W,  split_K, window_W, group_size);
    CHECK_ACL(aclrtSynchronizeStream(stream));

    printf("param3FileSize %zu \n", param3FileSize);
    CHECK_ACL(aclrtMemcpy(param3Host, param3FileSize, param3Device, param3FileSize, ACL_MEMCPY_DEVICE_TO_HOST));
    WriteFile("./output/output.bin", param3Host, param3FileSize);
    CHECK_ACL(aclrtFree(param3Device));
    CHECK_ACL(aclrtFreeHost(param3Host));

    CHECK_ACL(aclrtDestroyStream(stream));
    CHECK_ACL(aclrtDestroyContext(context));
    CHECK_ACL(aclrtResetDevice(deviceId));
    CHECK_ACL(aclFinalize());
#endif
    return 0;
}